package ru.vsu.amm.fuzzy.problems.ui;

import java.awt.CardLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;

import ru.vsu.amm.io.CommonIO;

/**
 * 
 * @author Иванов Илья
 * @since 20 января 2013
 *
 */
public class FuzzyFrame extends JFrame {

	private static final String TITLE = "Обобщённые оценки";
	private static final String VERSION = "1.0";
	private static final String BUILD_DATE = "22 января 2013";
	private static final String AUTHOR = "Иванов Илья";
	private static final String E_MAIL = "hour1scorp@gmail.com";
	
	private static final String HELP_RESOURCE_NAME = "help.html";
	private static final String DEFAULT_HELP_STRING = "<html><h3>Справка отсутствует</h3></html>";
	
	private static final String HELP;
	private static final String ABOUT;
	
	static {
		String help = CommonIO.readResourceAsString(FuzzyFrame.class, HELP_RESOURCE_NAME);
		HELP = help != null ? help : DEFAULT_HELP_STRING;
		
		StringBuffer about = new StringBuffer();
		about.append("<html>\n");
		about.append("<center>\n");
		about.append("<font color=\"green\">").append(TITLE).append("</font>\n");
		about.append("<br>\n");
		about.append("<br>\n");
		about.append("Версия: ").append(VERSION).append('\n');
		about.append("<br>\n");
		about.append("Дата сборки: ").append(BUILD_DATE).append('\n');
		about.append("<br><br>\n");
		about.append("Автор: ").append(AUTHOR).append('\n');
		about.append("<br>\n");
		about.append("E-mail: ").append(E_MAIL).append('\n');
		about.append("</center>\n");
		about.append("</html>");		
		ABOUT = about.toString();
	}
	
	private static final long serialVersionUID = -493574122778338709L;
	
	private OperatorController currentController;
	
	private JPanel contentPane;
	private JTextField scoresFilePath;
	private JTextField exponent;
	private JTextField additionalFilePath;
	
	private JRadioButton function;
	private JRadioButton comparisons;
	private JRadioButton weights;
	
	private JPanel cardsPanel;
	private JPanel exponentCard;
	private JPanel fileCard;
	private static final String[] CARDS_NAMES = { "exponent", "file"};
	
	private static final String FILE_LABEL_FORMAT = "Введите путь или выберите файл %s";
	private static final String FILE_SCORES = "с векторами оценок";
	private static final String FILE_PAIRED_COMPARISONS = "с матрицей парных сравнений";
	private static final String FILE_CUSTOM_WEIGHTS = "с вектором весов";
	private JLabel chooseAdditionalFileLabel;
	
	private static final String MODE_FORMAT = "[%s]";
	private JLabel mode;
	
	private JFileChooser fileChooser;
	private JButton chooseScoresFile;
	private JButton chooseAdditionalFile;
	private JMenu menuFile;
	private JCheckBox outputWeights;
	
	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					FuzzyFrame frame = new FuzzyFrame();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public FuzzyFrame() {
		setResizable(false);
		setTitle("Обобщённые оценки");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 678, 290);
		
		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		
		menuFile = new JMenu("Файл");
		menuBar.add(menuFile);
		
		ButtonGroup fileItemsGroup = new ButtonGroup();
		for (OperatorController controller : OperatorController.values()) {
			JMenuItem item = controller.getMenuItem(this);
			fileItemsGroup.add(item);
			menuFile.add(item);
		}
		
		JSeparator separator = new JSeparator();
		menuFile.add(separator);
		
		JMenuItem exitMenuItem = new JMenuItem("Выход");
		exitMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				exit();
			}
		});
		menuFile.add(exitMenuItem);
		
		JMenu menuHelp = new JMenu("Справка");
		menuBar.add(menuHelp);
		
		JMenuItem menuItemShowHelp = new JMenuItem("Показать справку");
		menuItemShowHelp.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				showHelp();
			}
		});
		menuHelp.add(menuItemShowHelp);
		
		JSeparator helpMenuSeparator = new JSeparator();
		menuHelp.add(helpMenuSeparator);
		
		JMenuItem menuItemAbout = new JMenuItem("О программе");
		menuItemAbout.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				showAbout();
			}
		});
		menuHelp.add(menuItemAbout);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(0, 0, 0, 0));
		setContentPane(contentPane);
		contentPane.setLayout(null);
		
		JPanel quantifiersPanel = new JPanel();
		quantifiersPanel.setBorder(new LineBorder(new Color(0, 0, 0)));
		FlowLayout fl_quantifiersPanel = (FlowLayout) quantifiersPanel.getLayout();
		fl_quantifiersPanel.setAlignment(FlowLayout.LEFT);
		quantifiersPanel.setBounds(12, 94, 152, 95);
		contentPane.add(quantifiersPanel);
		
		function = getRadioButton("Q(x) = x^a", CARDS_NAMES[0]);
		quantifiersPanel.add(function);
		
		comparisons = getRadioButton("Парные сравнения", CARDS_NAMES[1]);
		quantifiersPanel.add(comparisons);
		
		weights = getRadioButton("Задать вектор", CARDS_NAMES[1]);
		quantifiersPanel.add(weights);
		
		ButtonGroup radioGroup = new ButtonGroup();
		radioGroup.add(function);
		radioGroup.add(comparisons);
		radioGroup.add(weights);
		
		cardsPanel = new JPanel();
		cardsPanel.setBorder(new LineBorder(new Color(0, 0, 0)));
		cardsPanel.setBounds(176, 94, 485, 95);
		contentPane.add(cardsPanel);
		cardsPanel.setLayout(new CardLayout(0, 0));
		
		exponentCard = new JPanel();
		cardsPanel.add(exponentCard, CARDS_NAMES[0]);
		exponentCard.setLayout(null);
		
		JLabel exponentLabel = new JLabel("a =");
		exponentLabel.setVerticalAlignment(SwingConstants.TOP);
		exponentLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		exponentLabel.setBounds(12, 10, 29, 16);
		exponentCard.add(exponentLabel);
		
		exponent = new JTextField();
		exponent.setBounds(46, 10, 139, 20);
		exponentCard.add(exponent);
		exponent.setColumns(10);
		
		fileCard = new JPanel();
		cardsPanel.add(fileCard, CARDS_NAMES[1]);
		fileCard.setLayout(null);
		
		chooseAdditionalFileLabel = new JLabel(FILE_LABEL_FORMAT);
		chooseAdditionalFileLabel.setBounds(12, 7, 383, 16);
		fileCard.add(chooseAdditionalFileLabel);
		
		additionalFilePath = new JTextField();
		additionalFilePath.setColumns(10);
		additionalFilePath.setBounds(12, 34, 346, 23);
		fileCard.add(additionalFilePath);
		
		ActionListener chooseFileListener = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				chooseFile(e.getSource());
			}
		};
		
		chooseAdditionalFile = new JButton("Выбрать...");
		chooseAdditionalFile.addActionListener(chooseFileListener);
		chooseAdditionalFile.setBounds(370, 34, 100, 23);
		fileCard.add(chooseAdditionalFile);
		
		JPanel systemPanel = new JPanel();
		systemPanel.setBorder(new LineBorder(new Color(0, 0, 0)));
		systemPanel.setBounds(12, 12, 649, 70);
		contentPane.add(systemPanel);
		systemPanel.setLayout(null);
		
		JLabel chooseScoresFileLabel = new JLabel(String.format(FILE_LABEL_FORMAT, FILE_SCORES));
		chooseScoresFileLabel.setBounds(12, 12, 316, 16);
		systemPanel.add(chooseScoresFileLabel);
		
		scoresFilePath = new JTextField();
		scoresFilePath.setBounds(12, 32, 346, 23);
		systemPanel.add(scoresFilePath);
		scoresFilePath.setColumns(10);
		
		chooseScoresFile = new JButton("Выбрать...");
		chooseScoresFile.addActionListener(chooseFileListener);
		chooseScoresFile.setBounds(370, 32, 100, 23);
		systemPanel.add(chooseScoresFile);
		
		mode = new JLabel("[Режим]");
		mode.setBounds(525, 9, 112, 22);
		systemPanel.add(mode);
		mode.setHorizontalAlignment(SwingConstants.RIGHT);
		mode.setForeground(Color.RED);
		
		JButton calculate = new JButton("Вычислить");
		calculate.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				currentController.calculate(FuzzyFrame.this);
			}
		});
		calculate.setBounds(547, 203, 100, 23);
		contentPane.add(calculate);
		
		outputWeights = new JCheckBox("Вывести вектор весов в выходной файл");
		outputWeights.setBounds(274, 202, 265, 24);
		contentPane.add(outputWeights);
		
		setCurrentController(OperatorController.CONVOLUTION, true);
	}
	
	private JRadioButton getRadioButton(String text, final String cardName) {
		@SuppressWarnings("serial")
		final JRadioButton radio = new JRadioButton(text) {
			public void setSelected(boolean selected) {
				super.setSelected(selected);
				if (!selected)
					return;
				
				changeCard(cardName);
				if (this == comparisons)
					chooseAdditionalFileLabel.setText(String.format(FILE_LABEL_FORMAT, FILE_PAIRED_COMPARISONS));
				else if (this == weights)
					chooseAdditionalFileLabel.setText(String.format(FILE_LABEL_FORMAT, FILE_CUSTOM_WEIGHTS));
			}
		};
		
		radio.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				JRadioButton button = (JRadioButton) e.getSource();
				if (!button.isSelected())
					return;
				
				changeCard(cardName);
				if (button == comparisons)
					chooseAdditionalFileLabel.setText(String.format(FILE_LABEL_FORMAT, FILE_PAIRED_COMPARISONS));
				else if (button == weights)
					chooseAdditionalFileLabel.setText(String.format(FILE_LABEL_FORMAT, FILE_CUSTOM_WEIGHTS));
			}
		});
		
		return radio;
	}
	
	private void changeCard(String cardName) {
		CardLayout layout = (CardLayout) cardsPanel.getLayout();
		layout.show(cardsPanel, cardName);
	}
	
	private JFileChooser getFileChooser() {
		if (fileChooser == null) {
			fileChooser = new JFileChooser();
			fileChooser.setMultiSelectionEnabled(false);
		}
		
		fileChooser.setSelectedFile(null);
		return fileChooser;
	}
	
	private void chooseFile(Object source) {
		JFileChooser fileChooser = getFileChooser();
		fileChooser.showOpenDialog(this);
		if (fileChooser.getSelectedFile() == null)
			return;
		
		String path = fileChooser.getSelectedFile().getAbsolutePath();
		if (source == chooseAdditionalFile)
			additionalFilePath.setText(path);
		else if (source == chooseScoresFile)
			scoresFilePath.setText(path);
	}
	
	private void showHelp() {
		new HelpViewer(this, HELP);
	}
	
	private void showAbout() {
		new AboutDialog(this, ABOUT);
	}
	
	private static void exit() {
		System.exit(0);
	}
	
	public void setCurrentController(OperatorController controller, boolean checkMenuItems) {
		if (controller == null)
			return;
		
		currentController = controller;
		currentController.updateContent(this);
		
		if (checkMenuItems)
			for (int i = 0; i < menuFile.getItemCount(); i++) {
				JMenuItem item = menuFile.getItem(i);
				if (!(item instanceof OperatorController.OperatorMenuItem) ||
					((OperatorController.OperatorMenuItem) item).getController() != currentController)
					continue;
				
				item.setSelected(true);
				break;
			}
	}
	
	public void showConvolution() {
		mode.setText(String.format(MODE_FORMAT, OperatorController.CONVOLUTION.getText()));
		
		function.setEnabled(false);
		comparisons.setEnabled(true);
		weights.setEnabled(true);
		
		comparisons.setSelected(true);
	}
	
	public void showOwaLowa(String text) {
		mode.setText(String.format(MODE_FORMAT, text));
		
		function.setEnabled(true);
		comparisons.setEnabled(false);
		weights.setEnabled(false);
		
		function.setSelected(true);
	}
	
	public void showLMinLMax() {
		mode.setText(String.format(MODE_FORMAT, OperatorController.LMIN_LMAX.getText()));
		
		function.setEnabled(false);
		comparisons.setEnabled(false);
		weights.setEnabled(true);
		
		weights.setSelected(true);
	}
	
	public String getScoresFilePath() {
		return scoresFilePath.getText();
	}
	
	public String getAdditionalFilePath() {
		return additionalFilePath.getText();
	}
	
	public String getExponent() {
		return exponent.getText();
	}
	
	public boolean isPairedComparisons() {
		return comparisons.isSelected();
	}
	
	public boolean isCustomWeights() {
		return weights.isSelected();
	}
	
	public boolean isOutputWeights() {
		return outputWeights.isSelected();
	}
	
	public void showErrorMessage(String message) {
		if (message == null)
			return;
		
		JOptionPane.showMessageDialog(this, message, "Ошибка!", JOptionPane.ERROR_MESSAGE);
	}
	
	public void showInformMessage(String message) {
		JOptionPane.showMessageDialog(this, message, "Информация", JOptionPane.INFORMATION_MESSAGE);
	}
	
	public void showExclamationMessage(String message) {
		JOptionPane.showMessageDialog(this, message, "Внимание!", JOptionPane.WARNING_MESSAGE);
	}
	
	public String chooseFileForSaving() {
		JFileChooser fileChooser = getFileChooser();
		fileChooser.showSaveDialog(this);
		if (fileChooser.getSelectedFile() == null)
			return null;
		
		return fileChooser.getSelectedFile().getAbsolutePath();
	}
}